package com.oneproject.infrastructure.data.unitofwork;

import com.oneproject.domain.Entity;
import com.oneproject.domain.UnitOfWork;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tk.mybatis.mapper.common.Mapper;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 默认的UnitOfWork实现
 *
 * @author 马文韬
 * @date 2018/9/10
 * @version 1.0
 */
public abstract class BaseMybatisUnitOfWork extends DbContext implements UnitOfWork {

    private static Logger logger = LoggerFactory.getLogger(BaseMybatisUnitOfWork.class);

    private final SqlSessionFactory sqlSessionFactory;

    private final Map<Class<?>, Class<?>> mappers = new HashMap<Class<?>, Class<?>>();

    private SqlSession session = null;

    public BaseMybatisUnitOfWork(SqlSessionFactory sqlSessionFactory){
        this.sqlSessionFactory = sqlSessionFactory;
        modelCreating();
    }

    @Override
    protected void onModelCreated() {

        SqlSession session = getSession();
        Collection<Class<?>> mappers = session.getConfiguration().getMapperRegistry().getMappers();

        for (Class<?> keyClazz:
                modelMap.keySet()) {
            String keyClazzSimpleName = keyClazz.getSimpleName();
            for (Class<?> mapperClazz:
                 mappers) {
                String mapperClazzSimpleName = mapperClazz.getSimpleName();
                String mapperEntrySimpleName =
                        mapperClazzSimpleName.substring(0, mapperClazzSimpleName.lastIndexOf("Mapper"));

                if (keyClazzSimpleName.equals(mapperEntrySimpleName)) {
                    this.mappers.put(keyClazz, mapperClazz);
                    break;
                }
            }
        }
    }

    public <E extends Entity> E selectByPrimaryKey(Object id, Class<E> entryClazz) {
        return (E) getMapper(entryClazz).selectByPrimaryKey(id);
    }

    public <E extends Entity> Collection<E> selectAll(Class<E> entryClazz) {
        return (Collection<E>) getMapper(entryClazz).selectAll();
    }

    public <E extends Entity> List<E> select() {
        return null;
    }

    public <E extends Entity> void insert(E entity) {
        getMapper(entity.getClass()).insert(entity);
    }

    public <E extends Entity> void delete(E entity) {
        getMapper(entity.getClass()).delete(entity);
    }

    public <E extends Entity> void update(E entity) {
        getMapper(entity.getClass()).updateByPrimaryKey(entity);
    }

    public void commit() {
        getSession().commit();
        closeSession();
    }

    public void rollback() {
        getSession().rollback();
        closeSession();
    }

    private Mapper getMapper(Class<?> entryClazz) {
        Class<?> mapperClazz = this.mappers.get(entryClazz);
        return (Mapper) getSession().getMapper(mapperClazz);
    }

    private SqlSession getSession() {
        if (session == null) {
            session = sqlSessionFactory.openSession();
        }

        return session;
    }

    private void closeSession() {
        session.close();
        session = null;
    }
}
